#include "Binding/BoundBinaryOperator.hpp"
#include <memory>

#define STR(s) #s

#define MakeKindName(kind)          \
    {                               \
        BoundBinaryOperatorKind::kind, STR(kind) \
    }

std::map<BoundBinaryOperatorKind, std::string> BoundBinaryOperator::KindAllName
{
    MakeKindName(Error),
    MakeKindName(Addition),
    MakeKindName(Subtraction),
    MakeKindName(Multiplication),
    MakeKindName(Division),
    MakeKindName(Remainder),
    MakeKindName(LogicalAnd),
    MakeKindName(LogicalOr),
    MakeKindName(BitwiseOR),
    MakeKindName(BitwiseAnd),
    MakeKindName(BitwiseXor),
    MakeKindName(Equals),
    MakeKindName(NotEquals),
    MakeKindName(Less),
    MakeKindName(LessOrEquals),
    MakeKindName(Greater),
    MakeKindName(GreaterOrEquals)
};

#define MakeBinaryOperator(x) std::make_shared<BoundBinaryOperator> x

std::vector<SharedBoundBinaryOperator> BoundBinaryOperator::_operators = {
    MakeBinaryOperator((SyntaxKind::Plus, BoundBinaryOperatorKind::Addition, TypeSymbol::GetInt())),
    MakeBinaryOperator((SyntaxKind::Minus, BoundBinaryOperatorKind::Subtraction, TypeSymbol::GetInt())),
    MakeBinaryOperator((SyntaxKind::Star, BoundBinaryOperatorKind::Multiplication, TypeSymbol::GetInt())),
    MakeBinaryOperator((SyntaxKind::Slash, BoundBinaryOperatorKind::Division, TypeSymbol::GetInt())),
    MakeBinaryOperator((SyntaxKind::Mod, BoundBinaryOperatorKind::Remainder, TypeSymbol::GetInt())),

    MakeBinaryOperator((SyntaxKind::Ampersand, BoundBinaryOperatorKind::BitwiseAnd, TypeSymbol::GetInt())),
    MakeBinaryOperator((SyntaxKind::Pipe, BoundBinaryOperatorKind::BitwiseOR, TypeSymbol::GetInt())),
    MakeBinaryOperator((SyntaxKind::Hat, BoundBinaryOperatorKind::BitwiseXor, TypeSymbol::GetInt())),

    MakeBinaryOperator((SyntaxKind::Equals, BoundBinaryOperatorKind::Equals, TypeSymbol::GetInt(), TypeSymbol::GetBool())),
    MakeBinaryOperator((SyntaxKind::BangEquals, BoundBinaryOperatorKind::NotEquals, TypeSymbol::GetInt(), TypeSymbol::GetBool())),
    MakeBinaryOperator((SyntaxKind::Less, BoundBinaryOperatorKind::Less, TypeSymbol::GetInt(), TypeSymbol::GetBool())),
    MakeBinaryOperator((SyntaxKind::LessOrEquals, BoundBinaryOperatorKind::LessOrEquals, TypeSymbol::GetInt(), TypeSymbol::GetBool())),
    MakeBinaryOperator((SyntaxKind::Greater, BoundBinaryOperatorKind::Greater, TypeSymbol::GetInt(), TypeSymbol::GetBool())),
    MakeBinaryOperator((SyntaxKind::GreaterOrEquals, BoundBinaryOperatorKind::GreaterOrEquals, TypeSymbol::GetInt(), TypeSymbol::GetBool())),

    MakeBinaryOperator((SyntaxKind::Ampersand, BoundBinaryOperatorKind::BitwiseAnd, TypeSymbol::GetBool())),
    MakeBinaryOperator((SyntaxKind::AmpersandAmpersand, BoundBinaryOperatorKind::LogicalAnd, TypeSymbol::GetBool())),
    MakeBinaryOperator((SyntaxKind::Pipe, BoundBinaryOperatorKind::BitwiseOR, TypeSymbol::GetBool())),
    MakeBinaryOperator((SyntaxKind::PipePipe, BoundBinaryOperatorKind::LogicalOr, TypeSymbol::GetBool())),
    MakeBinaryOperator((SyntaxKind::Hat, BoundBinaryOperatorKind::BitwiseXor, TypeSymbol::GetBool())),

    MakeBinaryOperator((SyntaxKind::Equals, BoundBinaryOperatorKind::Equals, TypeSymbol::GetBool())),
    MakeBinaryOperator((SyntaxKind::BangEquals, BoundBinaryOperatorKind::NotEquals, TypeSymbol::GetBool())),

    MakeBinaryOperator((SyntaxKind::Plus, BoundBinaryOperatorKind::Addition, TypeSymbol::GetString())),

};

#undef MakeBinaryOperator
#undef STR
#undef MakeKindName
